package com.ybwh.springboot2.common.mybatis.plugin.result.sensitive2;

import cn.hutool.core.util.ReflectUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.Objects;

@Service
@RequiredArgsConstructor
public class AesServiceImpl {


    /**
     * 加密所需字段
     * @param declaredFields 字段
     * @param paramsObject 参数
     * @return 参数
     * @param <T> 参数类型
     * @throws Exception 异常
     */
    public <T> T encrypt(Field[] declaredFields, T paramsObject) throws Exception {
        for (Field field : declaredFields) {
            // 取出所有被SensitiveField注解的字段
            SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
            if (Objects.isNull(sensitiveField)) {
                continue;
            }
            field.setAccessible(true);
            Object object = field.get(paramsObject);
            // 暂时只实现String类型的加密
            if (object instanceof String) {
                String value = (String)object;
                // 如果映射字段值为空,并且以==结尾则跳过不进行加密
                if (StringUtils.isEmpty(value) || AesUtil.isBase64(value)) {
                    continue;
                }
                // 加密 这里我使用自定义的AES加密工具
                field.set(paramsObject, AesUtil.encryptBase64(value, sensitiveField.key()));
            }
        }
        return paramsObject;

    }

    /**
     * 解密
     * @param result 查询结果
     * @return 解密结果
     * @param <T> 结果类
     * @throws Exception 异常
     */
    public <T> T decrypt(T result) throws Exception {
        // 取出resultType的类
        Class<?> resultClass = result.getClass();
        Field[] allFields = ReflectUtil.getFields(resultClass);
        // Field[] declaredFields = resultClass.getDeclaredFields();
        for (Field field : allFields) {
            // 取出所有被SensitiveField注解的字段
            SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
            if (Objects.isNull(sensitiveField)) {
                continue;
            }
            field.setAccessible(true);
            Object object = field.get(result);
            // 只支持String的解密
            if (object instanceof String) {
                String value = (String)object;
                // 如果映射字段值为空,并且不已==结尾则跳过不进行解密
                if (StringUtils.isBlank(value) || !AesUtil.isBase64(value)) {
                    continue;
                }
                // 对注解的字段进行逐一解密
                field.set(result, AesUtil.decryptStr(value, sensitiveField.key()));
            }
        }
        return result;
    }

    /**
     * 判断是否被标记了加密
     * @param aClass    实体类
     * @return  是否被标记了加密
     */
    public boolean annotatedWithSensitive(Class<?> aClass) {
        SensitiveEntity annotation = AnnotationUtils.findAnnotation(aClass, SensitiveEntity.class);
        return annotation!=null;
    }

    /**
     * 解密所需字段
     * @param parameter
     * @throws IllegalAccessException
     */
    public void encryptParameter(Object parameter) throws IllegalAccessException {
        // 在此处编写对参数进行加密的逻辑
        // 根据您的加密算法和需求，对参数进行加密处理
        // 获取参数的类信息
        Class<?> parameterType = parameter.getClass();

        // 遍历参数的字段，查找被注解 @SensitiveField 标注的字段
        Field[] fields = ReflectUtil.getFields(parameterType);
        for (Field field : fields) {
            if (field.isAnnotationPresent(SensitiveField.class)) {

                SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);

                // 设置访问权限，允许访问私有字段
                field.setAccessible(true);

                // 获取字段的值
                Object value = field.get(parameter);

                if (value instanceof String) {
                    String value1 = (String)value;
                    // 对字段的值进行加密处理
                    Object encryptedValue = AesUtil.encryptBase64(value1, sensitiveField.key());

                    // 设置加密后的值
                    field.set(parameter, encryptedValue);
                }
            }
        }
    }

    /**
     * 判断是否包含需要加解密对象
     *
     * @param object 参数
     * @return 结果
     */
    public boolean needToDecrypt(Object object) {
        if (Objects.isNull(object)) {
            return false;
        }
        Class<?> objectClass = object.getClass();
        Class<?> parentClass = objectClass.getSuperclass();
        SensitiveEntity sensitiveEntity = AnnotationUtils.findAnnotation(objectClass, SensitiveEntity.class);
        SensitiveEntity parentSensitiveEntity = AnnotationUtils.findAnnotation(parentClass, SensitiveEntity.class);

        return Objects.nonNull(sensitiveEntity) || Objects.nonNull(parentSensitiveEntity);
    }
}